﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Maps.MapControl;
using System.Collections.Generic;

namespace SilverlightMapCreator.Mathemathics
{
    public class CorrespondenceSystem
    {
        private double c00, c01, c02, c10, c11, c12;

        public void ComputeParameters(List<Corespondence> corespondances)
        {
            //the formula which defines the corespondance between map and picture
            //sx = c00*rx + c01*ry + c02
            //sy = c10*rx + c11*ry + c12

            double[] sx = new double[corespondances.Count];
            double[] sy = new double[corespondances.Count];
            double[] ry = new double[corespondances.Count];
            double[] rx = new double[corespondances.Count];

            for (int i = 0; i < corespondances.Count; i++)
            {
                sx[i] = MercatorProjection.lonToX(corespondances[i].Location.Longitude);
                sy[i] = MercatorProjection.latToY(corespondances[i].Location.Latitude);
                rx[i] = corespondances[i].Point.X;
                ry[i] = corespondances[i].Point.Y;
            }

            double[,] matrix = { { rx[0], rx[1], rx[2] }, { ry[0], ry[1], ry[2] }, { 1, 1, 1 } };
            double[,] right = { { sx[0], sx[1], sx[2] }, { sy[0], sy[1], sy[2] }, { 1, 1, 1 } };

            //Utils.Print(matrix);
            //Utils.Print(right);
            var inverse = MatrixLibrary.Matrix.Inverse(matrix);


            var transform = MatrixLibrary.Matrix.Multiply(right, inverse);

            //Utils.Print(transform);

            c00 = transform[0, 0];
            c01 = transform[0, 1];
            c02 = transform[0, 2];

            c10 = transform[1, 0];
            c11 = transform[1, 1];
            c12 = transform[1, 2];

            //Another way which could have been used to compute the parameters
            //Linear solving and multiplication by inverse matrix are generally the same

            //MatrixLibrary.Matrix a = new MatrixLibrary.Matrix(6, 6);
            //MatrixLibrary.Matrix b = new MatrixLibrary.Matrix(6, 1);


            ////initialize the matrix
            //for (int i = 0; i < 3; i++)
            //{

            //    //right hand side
            //    b[2 * i, 0] = sx[i];
            //    b[2 * i + 1, 0] = sy[i];

            //    //even rows
            //    a[2 * i, 0] = rx[i];
            //    a[2 * i, 1] = ry[i];
            //    a[2 * i, 2] = 1;
            //    a[2 * i, 3] = 0;
            //    a[2 * i, 4] = 0;
            //    a[2 * i, 5] = 0;

            //    //odd rows
            //    a[2 * i + 1, 0] = 0;
            //    a[2 * i + 1, 1] = 0;
            //    a[2 * i + 1, 2] = 0;
            //    a[2 * i + 1, 3] = rx[i];
            //    a[2 * i + 1, 4] = ry[i];
            //    a[2 * i + 1, 5] = 1;
            //}

            //String aStr = MatrixLibrary.Matrix.PrintMat(a);
            //Debug.WriteLine(aStr);

            //String bStr = MatrixLibrary.Matrix.PrintMat(b);
            //Debug.WriteLine(bStr);

            //var result = MatrixLibrary.Matrix.SolveLinear(a, b);

            //Print(result.toArray);
            //c00 = result[0, 0];
            //c01 = result[1, 0];
            //c02 = result[2, 0];

            //c10 = result[3, 0];
            //c11 = result[4, 0];
            //c12 = result[5, 0];
        }

        public Location PointToLocationAffinity(double x, double y)
        {
            double longitude = c00 * x + c01 * y + c02;
            double latitude = c10 * x + c11 * y + c12;

            var mercatorX = MercatorProjection.xToLon(longitude);
            var mercatorY = MercatorProjection.yToLat(latitude);
            Location location = new Location(mercatorY, mercatorX);
            return location;
        }
    }
}
